/*!
 * 任务执行队列模块
 * @author: __author__
 * @version: __buildVersion__
 * @buildDate：__buildDate__
 */
export let version: string = '__buildVersion__';

interface I_TASK_FN {
    (resolve: (data?: any) => void, reject: (err?: any) => void): void
}

interface I_TASK {
    fn: I_TASK_FN,
    status: TaskStatus,
    resolve: (data: any) => void,
    reject: (err: any) => void
};

interface I_TASK_EVENT_FN {
    (eventName: string, eventData: any): void
};

interface I_TASK_EVENTS {
    [eventName: string]: I_TASK_EVENT_FN[]
};

interface I_TASK_GROUP_OPTS {

    /** 允许同时执行的任务数 */
    allowTasks: number,

    /** 是否自动执行任务 */
    autoRun: boolean

};

interface I_TASK_GROUP {
    name: string,
    allowTasks: number, // 允许同时运行的任务数
    willStop: boolean, // 设置停止状态标识
    autoRun: boolean, // 添加自动运行

    total: number,
    finished: number,
    running: number,
    errored: number,

    tasks: I_TASK[] //任务列表
};

interface I_TASK_GROUPS {
    [groupName: string]: I_TASK_GROUP
};

const enum TaskStatus { wait, progress, finish, error };

// 配置
export let config = {

    /** 自动删除完成的任务 */
    autoRemovefinished: true

};

let events: I_TASK_EVENTS = {};

let groups: I_TASK_GROUPS = {

    'default': {
        name: 'default',
        allowTasks: 1,// 允许同时运行的任务数
        willStop: false,
        autoRun: true,
        total: 0,
        finished: 0,
        running: 0,
        errored: 0,
        tasks: []
    }

};

/** 创建任务 */
function add(fn: I_TASK_FN, groupName = 'default'): Promise<any> {

    let group: I_TASK_GROUP = groups[groupName];

    if (!groups[groupName]) {
        throw Error(`Group "${groupName}" does not exist`);
    }

    group.total++;

    return new Promise((resolve, reject) => {

        let task: I_TASK = {
            fn,
            status: 0,
            resolve,
            reject,
        };

        group.tasks.push(task);
        trigger('add', { groups, group, task });

        // 自动运行task任务列表
        if (group.autoRun) {
            run(groupName);
        }

    });

}

/** 绑定事件 */
function on(eventName: string, fn: I_TASK_EVENT_FN): void {

    if (eventName === '') {
        return;
    }

    let eventNames = eventName.trim().split(' ');
    if (eventNames.length > 1) {
        eventNames.forEach(eventName => {
            on(eventName, fn);
        });
        return;
    }

    if (!events[eventName]) {
        events[eventName] = []
    }

    events[eventName].push(fn);

}

/** 移除事件 */
function off(eventName: string, fn?: I_TASK_EVENT_FN): void {

    if (eventName === '') {
        return;
    }

    let eventNames = eventName.trim().split(' ');
    if (eventNames.length > 1) {
        eventNames.forEach(eventName => {
            off(eventName, fn);
        });
        return;
    }

    if (events[eventName]) {
        for (let i = 0; i < events[eventName].length; i++) {
            if (fn === undefined || events[eventName][i] === fn) {
                events[eventName].splice(i, 1);
                break;
            }
        }
    }

}

/** 触发事件 */
function trigger(eventName: 'add' | 'start' | 'end' | 'error' | 'progress', eventData: any): void {

    if (events[eventName]) {
        events[eventName].forEach(fn => {
            fn(eventName, eventData);
        });
    }

}

/** 创建、编辑组 */
function setGroup(groupName = '', groupOpts: I_TASK_GROUP_OPTS = { allowTasks: 1, autoRun: true }): I_TASK_GROUP {

    if (!groups[groupName]) {
        groups[groupName] = {
            name: groupName,
            allowTasks: 1,// 允许同时运行的任务数
            willStop: false,
            autoRun: true,
            total: 0,
            finished: 0,
            running: 0,
            errored: 0,
            tasks: [] //任务列表
        }
    }

    groups[groupName] = { ...groups[groupName], ...groupOpts };

    return groups[groupName];

}

/** 获得组 */
function getGroup(groupName = 'default'): I_TASK_GROUP {
    return groups[groupName];
}

/** 获得全部组 */
function getGroups(): I_TASK_GROUPS {
    return groups;
}

/** 停止任务组队列 */
function stop(groupName = 'default'): void {
    let group = groups[groupName];

    if (group) {
        group.willStop = true;
    }
}

/** 开始任务组队列 */
function start(groupName = 'default'): void {

    let group = groups[groupName];

    if (group) {
        group.willStop = false;
        run(groupName);
    }

}

/** 执行任务队列 */
function run(groupName = 'default'): void {

    let group = groups[groupName];
    let tasks = group.tasks;

    // 停止Run
    if (group.willStop) {
        return;
    }

    // 如果有空余队列
    for (let i = 0; i < tasks.length; i++) {
        if (group.running < group.allowTasks) {

            let task = tasks[i];

            if (task.status === TaskStatus.wait) {

                group.running++;
                task.status = TaskStatus.progress;
                new Promise(task.fn).then(res => {

                    //移除任务(考虑到并行的>1的任务数，要重新查找下)
                    task.status = TaskStatus.finish;

                    if (config.autoRemovefinished) {
                        tasks.splice(tasks.findIndex(task2 => task2 === task), 1);
                    }

                    group.running--;
                    group.finished++;

                    task.resolve(res);
                    trigger('end', { groups, group, task });
                    trigger('progress', { groups, group, task, progress: getGroupProgressData(groupName) });
                    run(groupName);
                    return res;

                }).catch(err => {

                    task.status = TaskStatus.error;
                    group.running--;
                    group.errored++;

                    task.reject(err);
                    console.error(err);
                    trigger('error', { groups, group, task });
                    run(groupName);
                    return err;

                });

                trigger('start', { groups, group, task });

            }

        } else {
            break;
        }
    }

}

/** 移除任务 */
function remove(fn: I_TASK_FN, groupName = 'default'): boolean {

    let group = groups[groupName];
    if (group) {

        for (let i = 0; i < group.tasks.length; i++) {
            let task: I_TASK = group.tasks[i];
            if (task.fn === fn) {
                group.tasks.splice(i, 1);
                group.total--;
                return true;
            }
        }
    }

    return false;

}

// 获得组的进度状态数据
function getGroupProgressData(groupName = 'default'): any {

    let group = groups[groupName];

    return {
        groupName,
        total: group.total,
        finished: group.finished,
        running: group.running,
        errored: group.errored,
        percent: (group.finished + group.errored) / group.total
    }

}

export default {
    version,
    config,
    add,
    start,
    stop,
    remove,
    on, //start, end, error, progress
    off,
    setGroup,
    getGroup,
    getGroups
}